package org.apache.felix.dm.impl.dependencies.bi;

import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;

import org.apache.felix.dm.Dependency;
import org.apache.felix.dm.DependencyActivation;
import org.apache.felix.dm.DependencyService;

@SuppressWarnings("rawtypes")
public class ManagedDependency implements Dependency, DependencyActivation, Runnable {
	private final Toggle m_toggle;

	private final List<DependencyService> m_services = new ArrayList<DependencyService>();

	private boolean instanceBound = false;

	private boolean persistent = false;

	public ManagedDependency(Toggle toggle) {
		this.m_toggle = toggle;
	}

	public ManagedDependency(Toggle toggle, boolean instanceBound, boolean persistent) {
		this.m_toggle = toggle;
		this.instanceBound = instanceBound;
		this.persistent  = persistent;
	}

	public Dependency createCopy() {
		return new ManagedDependency(m_toggle);
	}

	public Object getAutoConfigInstance() {
		return "" + m_toggle.isAvailable();
	}

	public String getAutoConfigName() {
		return null;
	}

	public Class<?> getAutoConfigType() {
		return String.class;
	}

	public Dictionary getProperties() {
		return null;
	}

	public void run() {
		// invoked on every change
		if (m_toggle.isAvailable()) {
			Object[] services = m_services.toArray();
			for (int i = 0; i < services.length; i++) {
				DependencyService ds = (DependencyService) services[i];
				ds.dependencyAvailable(this);
				if (!isRequired()) {
					invokeAdded(ds);
				}
			}
		} else {
			Object[] services = m_services.toArray();
			for (int i = 0; i < services.length; i++) {
				DependencyService ds = (DependencyService) services[i];
				ds.dependencyUnavailable(this);
				if (!isRequired()) {
					invokeRemoved(ds);
				}
			}
		}
	}

	public void invokeAdded(DependencyService service) {
		invoke(service, "added");
	}

	public void invokeRemoved(DependencyService service) {
		invoke(service, "removed");
	}

	public void invoke(DependencyService dependencyService, String name) {
		if (name != null) {
			dependencyService.invokeCallbackMethod(getCallbackInstances(dependencyService), name, new Class[][] { { String.class }, { Object.class }, {} },
					new Object[][] { { getAutoConfigInstance() }, { getAutoConfigInstance() }, {} });
		}
	}

	private synchronized Object[] getCallbackInstances(DependencyService dependencyService) {
		return dependencyService.getCompositionInstances();
	}

	public boolean isAutoConfig() {
		return false;
	}

	public boolean isAvailable() {
		return m_toggle.isAvailable();
	}

	public boolean isInstanceBound() {
		return instanceBound;
	}

	public boolean isPropagated() {
		return false;
	}

	public boolean isRequired() {
		return true;
	}

	public void start(DependencyService service) {
		synchronized (this) {
			m_services.add(service);
		}
		m_toggle.setRunnable(this);
	}

	public void stop(DependencyService service) {
		synchronized (this) {
			m_services.remove(service);
		}
		m_toggle.setRunnable(null);
	}
	
	public boolean isPersistent() {
		return persistent;
	}

}
